/* ------------------------------------------------------------------------*
 * spi
 * ------------------------------------------------------------------------*/
#include "bsp.h" 
#include "bsp_i2s.h"
#include "bsp_dma.h" 
#include "pincfg.h" 
#include "os_obj.h" 

#define I2SX       I2S0
#define I2SX_IRQn   I2S0_IRQn
#define I2S_BUFF_SIZE	2048

osSemaphoreDef(i2s_sem);

static volatile uint8_t dma_comp;
static void i2s_dma_call_back(int err);
static osSemaphoreId sid_i2s = 0;
static char bit_mode;

/*****************************************************************************
* @brief   hal init.
* @param   rate 采样率
* @return  none
* @ Pass/ Fail criteria: none
*****************************************************************************/
void bsp_i2s_init(uint32_t rate, uint32_t bits)
{
	I2S_Close(I2SX);
	
	// 打开 i2s
	I2S_Open(
	I2SX, 
	rate, 
	I2S_MODE_MASTER, 
	bits, 
	I2S_DISABLE_MONO, 
	I2S_FORMAT_I2S_MSB);
	
	switch(bits)
	{
		case I2S_DATABIT_8:
			bit_mode = 0;
		case I2S_DATABIT_16:
			bit_mode = 1;
		case I2S_DATABIT_24:
			bit_mode = 2;
		case I2S_DATABIT_32:
			bit_mode = 3;
	}
	
	// 创建信号量
	if(0  == sid_i2s)
	{
		sid_i2s = osSemaphoreCreate(osSemaphore(i2s_sem),1);
		osSemaphoreWait(sid_i2s, 0);
	}
}


/*****************************************************************************
* @brief   spi data write.
*****************************************************************************/
uint8_t bsp_i2s_play(int16_t(*dat_get)(void *buff, int16_t len_req))
{
	char dma_ch_tx = -1;
	pdma_basic_cfg_type dma_cfg;
	int16_t len_play;
	char * buf1, *buf0, sel;

	// 申请内存
	buf0 = malloc(I2S_BUFF_SIZE);
	buf1 = malloc(I2S_BUFF_SIZE);

	// dma 通道申请
	while (dma_ch_tx < 0)
	{
		dma_ch_tx = bsp_pdma_alloc();
		if (dma_ch_tx < 0)
		{
			osDelay(ms_ticks(10));
		}
	}

	// 使能发送
	I2S_ENABLE_TX(I2SX);

	// 读数据
	sel = 0;
	len_play = dat_get(buf0, I2S_BUFF_SIZE);
	
	// 清信号量
	osSemaphoreWait(sid_i2s, 0);
	
	// 发送
	while (len_play > 0)
	{
		// 先关DMA
		I2S_DISABLE_TXDMA(I2SX);

		// 通道配置
		dma_cfg.req_src = PDMA_SPI1_TX;
		dma_cfg.prio = 0;
		dma_cfg.int_en = 1;
		dma_cfg.ctr_sa_mode = PDMA_SAR_INC;
		dma_cfg.ctr_da_mode = PDMA_DAR_FIX,
		dma_cfg.ctr_txt_mode = PDMA_REQ_SINGLE;
		switch(bit_mode)
		{
			case 0:
				dma_cfg.ctr_width = PDMA_WIDTH_8;
				dma_cfg.ctr_amount = len_play - 1;
				break;
			case 1:
				dma_cfg.ctr_width = PDMA_WIDTH_16;
				dma_cfg.ctr_amount = len_play/2 - 1;
				break;
			case 2:
				dma_cfg.ctr_width = PDMA_WIDTH_32;
				dma_cfg.ctr_amount = len_play/4 - 1;
				break;
			case 3:
				dma_cfg.ctr_width = PDMA_WIDTH_32;
				dma_cfg.ctr_amount = len_play/4 - 1;
				break;
		}
		
		if (0 == sel)
			dma_cfg.sa = (uint32_t)buf0;
		else
			dma_cfg.sa = (uint32_t)buf1;
		dma_cfg.da = (uint32_t)(&I2SX->TXFIFO);
		dma_cfg.call_back = i2s_dma_call_back;
		bsp_pdma_cfg(&dma_cfg, dma_ch_tx);

		// 开启DMA请求
		dma_comp = 0;
		I2S_ENABLE_TXDMA(I2SX);

		// 读下一buff
		sel = !sel;

		if (0 == sel)
			len_play = dat_get(buf0, I2S_BUFF_SIZE);
		else
			len_play = dat_get(buf1, I2S_BUFF_SIZE);

		// 等待I2S发送完成
		osSemaphoreWait(sid_i2s, ms_ticks(500));
		
		while (!dma_comp)
		{
			
		}
	}

	// 关闭发送
	I2S_DISABLE_TXDMA(I2SX);
	I2S_DISABLE_TX(I2SX);

	// 释放DMA通道
	bsp_pdma_free(dma_ch_tx);

	// 释放内存
	free(buf1);
	free(buf0);

	return (0);
}

/*****************************************************************************
* @brief   DMA 完成
*****************************************************************************/
void i2s_dma_call_back(int err)
{
	dma_comp = 1;
	osSemaphoreRelease(sid_i2s);
}
